import { getPermissionTree } from '@/services/permission';
import type { MergeDataNode } from '@/utils/permissionTree';
import { formatPermissionTreeToTreeFC } from '@/utils/permissionTree';
import { ResponseCode } from '@/utils/request';
import type { TreeProps } from 'antd';
import { message, Tree } from 'antd';
import type { Key } from 'react';
import React, { useEffect, useState } from 'react';
import TreeSelectTitleRender from '../TreeSelectTitleRender';

export type CheckInfo = Parameters<NonNullable<TreeProps['onCheck']>>[1];

const initChecked = () => ({ checked: [] as Key[], halfChecked: [] as Key[] });

export interface TreeSelectProps {
  value?: Key[];
  onChange?: (value: Key[], info: CheckInfo) => void;
  disabled?: boolean;
}

const TreeSelect: React.FC<TreeSelectProps> = ({ value, onChange, disabled }) => {
  const [expandedKeys, setExpandedKeys] = useState<React.Key[]>(['0-0-0', '0-0-1']);
  const [autoExpandParent, setAutoExpandParent] = useState<boolean>(true);

  const [treeData, setTreeData] = useState<MergeDataNode[]>([]);

  useEffect(() => {
    getPermissionTree().then(({ data, code, message: msg }) => {
      if (code === ResponseCode.Success) {
        const { permissionTree } = data;
        setTreeData(formatPermissionTreeToTreeFC(permissionTree));
      } else {
        message.error(msg);
      }
    });
  }, []);

  const onExpand = (expandedKeysValue: React.Key[]) => {
    setExpandedKeys(expandedKeysValue);
    setAutoExpandParent(false);
  };

  return (
    <Tree<MergeDataNode>
      disabled={disabled}
      checkable
      // 严格选择模式
      checkStrictly
      selectable={false}
      onExpand={onExpand}
      expandedKeys={expandedKeys}
      autoExpandParent={autoExpandParent}
      onCheck={(
        checkedKeysValue:
          | {
              checked: Key[];
              halfChecked: Key[];
            }
          | Key[],
        info,
      ) => {
        const { node, checked } = info;
        if (!Array.isArray(checkedKeysValue)) {
          const keysSet = new Set(checkedKeysValue.checked as number[]);
          // 菜单选中|取消选中，选择所有子集加入|删除
          if (node.funcType === '1' && node.children) {
            // 对node进行深度优先遍历，非递归的使用栈形式
            const progressStack: MergeDataNode[] = [];
            progressStack.push(node);
            while (progressStack.length) {
              // 弹出
              const curr = progressStack.shift() as MergeDataNode;
              // 访问
              keysSet[checked ? 'add' : 'delete'](curr.id);
              if (!curr.children?.length) continue;
              // 加入所有的子节点，这里加入的子节点的顺序决定了子节点的遍历顺序
              for (let i = 0; i < curr.children.length; i++) {
                progressStack.push(curr.children[i]);
              }
            }
          }

          // 将所有父级节点加入
          if (checked) {
            node.idPath.split('/').forEach((idStr) => {
              if (idStr) keysSet.add(Number(idStr));
            });
          } else {
            // 正常情况这里需要反向修改父级节点，当子集为空父级也为空
            // 但是这里不做任何操作，不让父节点永远无法单独选中
          }
          onChange?.(Array.from(keysSet), info);
        }
      }}
      // 有选项才写入数据
      checkedKeys={
        treeData.length ? { checked: value || [], halfChecked: [] } || initChecked() : initChecked()
      }
      treeData={treeData}
      showLine={{ showLeafIcon: false }}
      fieldNames={{
        title: 'znName',
        key: 'id',
        children: 'children',
      }}
      titleRender={(node) => {
        return <TreeSelectTitleRender node={node} />;
      }}
    />
  );
};

export default TreeSelect;
